package com.juhuixing.common.assembly.handler;

import com.juhuixing.common.base.BaseController;
import com.juhuixing.common.base.ResponseData;
import com.juhuixing.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ElementKind;
import javax.validation.Path;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

/**
 * 统一异常处理
 *
 * @author admin
 * @date 2018/4/22 13:52
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends BaseController {


    /**
     * 自定义异常处理
     * 自定义异常,属于某些情况下预期的异常，http返回状态为200， result中的code为-1，message为用户可读信息。
     * @param baseException 基础的异常
     * @return 失败的result
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResponseData handlerBaseException(BusinessException baseException) {
        log.error("handle baseException", baseException);
        return ResponseData.fail( baseException.getMessage(),baseException.getCode());
    }

    /**
    * 处理全局Exception,预期之外的异常， http返回状态为500， result中的code为500，message为开发人员可读信息.
    * @Author: 刘天元
    * @Date: 2018/6/1 17:15
    */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseData handlerException(Exception exception) {
        // 处理动态代理类中抛出的BaseException
        Throwable cause = exception.getCause();
        while (cause != null) {
            if(cause instanceof BusinessException) {
                BusinessException baseException = (BusinessException) cause;
                log.error("handle baseException", baseException);
                return ResponseData.fail(baseException.getMessage(),baseException.getCode());
            }
            cause = cause.getCause();
        }
        // 处理Exception
        log.error("handle exception", exception);
        StringWriter sw = new StringWriter();
        exception.printStackTrace(new PrintWriter(sw, true));
        String address = ServiceInfoUtil.getIp() + ":" + ServiceInfoUtil.getPort();
        return ResponseData.fail(address + sw.getBuffer().toString(),HttpStatus.INTERNAL_SERVER_ERROR.value());
    }

    /**
     * 处理参数校验异常， http返回状态为400， result中的code为400，message为开发人员可读信息.
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseData handleValidationException(ConstraintViolationException e){
        log.error("参数验证失败 : " + e);
        StringBuilder builder = new StringBuilder();
        for(ConstraintViolation<?> s:e.getConstraintViolations()){
            for(Path.Node node : s.getPropertyPath()) {
                if (ElementKind.PARAMETER.equals(node.getKind())) {
                    builder.append(node.getName());
                }
            }
            builder.append(":").append(s.getMessage()+" ");
        }
        return ResponseData.fail(builder.toString(),HttpStatus.BAD_REQUEST.value());
    }

    /**
     * 处理参数校验异常， http返回状态为400， result中的code为400，message为开发人员可读信息.
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseData handleMissingServletRequestParameterException(
            MissingServletRequestParameterException e) {
        log.error("缺少请求参数", e);
        return ResponseData.fail("缺少请求参数 "+e.getParameterName(),HttpStatus.BAD_REQUEST.value());
    }

    /**
     * 处理参数校验异常， http返回状态为400， result中的code为400，message为开发人员可读信息.
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数验证失败 : " + e);
        BindingResult result = e.getBindingResult();
        final List<FieldError> fieldErrors = result.getFieldErrors();
        StringBuilder builder = new StringBuilder();
        for (FieldError error : fieldErrors) {
            builder.append( error.getDefaultMessage()+"\n");
        }
        return ResponseData.fail( builder.toString(),HttpStatus.BAD_REQUEST.value());
    }
}
